package proyectoia;

import aima.search.framework.GoalTest;
import aima.search.framework.HeuristicFunction;
import aima.search.framework.Search;
import aima.search.framework.SuccessorFunction;
import aima.search.informed.SimulatedAnnealingSearch;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
import org.jfree.ui.RefineryUtilities;

public class StagedExperiment3 extends StagedExperiment {

    SuccessorFunction successor;
    Integer initial;
    SimulatedAnnealingSearch search;

    public StagedExperiment3(int seed, int nIterations, SuccessorFunction bestSuccessor, Integer bestInitial,
            Integer totalIterations, Integer iterations, Integer k, Double lambda) {
        super(seed, nIterations);
        numStages = 1;
        successor = bestSuccessor;
        initial = bestInitial;
        search = new SimulatedAnnealingSearch(totalIterations, iterations, k, lambda);
       //search.traceOn();



    }

    @Override
    protected int getNumUsers() {
        return 200;
    }

    @Override
    protected int getNumRequests() {
        return 5;
    }

    @Override
    protected int getNumServers() {
        return 50;
    }

    @Override
    protected int getNumReplications() {
        return 5;
    }

    @Override
    protected DistFileSystemState getInitialSolution(DistFileSystemState state) {
        switch (initial) {
            case GREEDY:
                state.generateGreedySolution();
                break;
            case RANDOM:
                state.generateRandomSolution(seed);
                break;
            case EMPTY:
                state.generateEmptySolution();
                break;
        }
        return state;
    }

    @Override
    protected Search getSearch() {
        return search;
    }

    @Override
    protected Integer getSearchResult() {
        return STATES;
    }
    
    @Override
    protected SuccessorFunction getSuccessor() {
        return successor;
    }

    @Override
    protected GoalTest getGoalTest() {
        return new DistFileSystemGoalTest();
    }

    @Override
    protected HeuristicFunction getHeuristic() {
        return new DistFileSystemHeuristicFunction1();
    }
    static LinkedBlockingDeque<Data> totalList = new LinkedBlockingDeque();
    
    
    private double getSpeedup(int s) throws Exception {
        DistFileSystemState initS = new DistFileSystemState(initialStates[s].get(0));
        DistFileSystemState lastS = getLastState(initS, searchAgents[s].get(0));
        int initTime = initS.getSlowestServerTime();
        int lastTime = lastS.getSlowestServerTime();
        return (double)initTime/(double)lastTime;
    } 
   
    public void printSAtune(PrintWriter o, int its, int steps, int k, double lam) throws Exception {
  
        
        for (int s = 0; s < numStages; s++) {
            SummaryStatistics is = new SummaryStatistics();
            for (int i = 0; i < numIterations; i++) {
                is.addValue(initialStates[s].get(i).getSlowestServerTime());
            }
            
           
            
            //System.out.println("Solució inicial per " + stageName(s));
            //System.out.println("El temps del servidor més lent triga de mitja " + (int) is.getMean() + " amb " + (int) is.getStandardDeviation() + " stdev.");
            SummaryStatistics ss = new SummaryStatistics();
            SummaryStatistics rt = new SummaryStatistics();
            
            DistFileSystemState initS = new DistFileSystemState(initialStates[s].get(0));
            DistFileSystemState lastS = getLastState(initS, searchAgents[s].get(0));
            int initTime = initS.getSlowestServerTime();
            int lastTime = lastS.getSlowestServerTime();


            
            o.println((double)initTime/(double)lastTime+" \t "+its+" \t "+steps+" \t "+k+" \t "+lam);

            //System.out.println(stageDescription(s));
            //System.out.println("El temps del servidor més lent triga de mitja " + (int) ss.getMean() + " amb " + (int) ss.getStandardDeviation() + " stdev, i triga " + (int) rt.getMean() + " milisegonds en calcular-se.");
        }
        //o.close();
    }
    
 
    
    public static void main(String[] args) throws InterruptedException, IOException {
        
        int db = 0;
        
        
        
        
        if (db == 0) {
            
            StagedExperiment3 se3 = new StagedExperiment3(0, 1, new DistFileSystemSuccessorFunctionSA1(), StagedExperiment.GREEDY,
                                150000, 500, 620, 0.00005);
            se3.initialitze();
            try {
//                Plotter plotter = new Plotter(totalList, se3.getNumServers(), "");
//                plotter.pack();
//                RefineryUtilities.centerFrameOnScreen(plotter);
//                plotter.setVisible(true); 
//                Thread t = new Thread (plotter, "plotter" );
//                t.start();
                se3.execute();
//                t.interrupt();
//                se3.printSlowestServerTime("experiment-3");
                
                
                DistFileSystemState state = (DistFileSystemState)se3.search.getGoalState();                          
                
                double origT = se3.initialStates[0].get(0).getSlowestServerTime();
                double finalT = state.getSlowestServerTime();
                double ganancia = origT-finalT;
                double execT = (double)se3.runTimes[0].get(0);
                double ratioT = ganancia/execT;
                
                
                System.out.println("Original time "+origT);
                System.out.println("Final time    "+finalT);
                System.out.println("Speedup       "+se3.getSpeedup(0));
                System.out.println("Gain          "+ganancia);
                System.out.println("ratioTime     "+ratioT);
                
                
                
            } catch (Exception ex) {
                Logger.getLogger(StagedExperiment3.class.getName()).log(Level.SEVERE, null, ex);
            }
            return;
        }
//        
//        FileWriter outFile = new FileWriter("data/X4-tuningSA.data");
//        PrintWriter o = new PrintWriter(outFile);
//        o.println("# Tune simualted anealing");
//        o.println("Mejora \t Its \t steps \t k \t lam");
//        
//        
//        int firstIts = 156250;
//        int firstSteps = 2;
//        int firstK = 625;
//        double firstLam = 100000;
//        
//        int lastIts = 1000000;
//        int lastSteps = 500;
//        int lastK = 625;
//        double lastLam = 1000000;
//        
//        double maxSpeedup = 1.0;
//        int bestIts = firstIts;
//        int bestSteps = firstSteps;
//        int bestK = firstK;
//        double bestLam = firstLam;
//        
//       
//        
//        for (int its = firstIts; its <= lastIts; its*=5){
//
//            for (int steps = firstSteps; steps <= lastSteps; steps*=steps) {
//
//                if (its%steps != 0) continue;
//                for (int k = firstK; k <= lastK; k *= 2) {
//                    for (double l = firstLam; l <= lastLam; l*=10) {
//                        Double lambda = 1/l;
//
//                        System.out.println("its="+its+", steps="+steps+", k =" + k + ", lambda=" + lambda);
//                        StagedExperiment3 se3 = new StagedExperiment3(123, 1, new DistFileSystemSuccessorFunctionSA1(), StagedExperiment.GREEDY,
//                                its, steps, k, lambda);
//
//
//                        try {
//                            se3.initialitze();
////                            Plotter plotter = new Plotter(totalList, se3.getNumServers(), "its= "+its+", steps= "+steps+", k = " + k + ", lambda = " + lambda);
////                            plotter.pack();
////                            RefineryUtilities.centerFrameOnScreen(plotter);
////                            plotter.setVisible(true); 
////                            Thread t = new Thread (plotter, "plotter" );
////                            t.start();
//                            se3.execute();
////                            t.interrupt();
//                           // se3.printSlowestServerTime("experiment-3");
//                            se3.printSAtune(o,its,steps,k,l);
//                            
//                            
//                            DistFileSystemState state = (DistFileSystemState)se3.search.getGoalState();
//                            System.out.println("Original time "+se3.initialStates[0].get(0).getSlowestServerTime());
//                            System.out.println("Final time    "+state.getSlowestServerTime());
//                            System.out.println("Speedup       "+se3.getSpeedup(0));
//                            
//                            if (se3.getSpeedup(0) > maxSpeedup) {
//                                maxSpeedup = se3.getSpeedup(0);
//                                bestLam = l;
//                                bestK = k;
//                                bestIts = its;
//                                bestSteps = steps;
//                            }
//                             System.out.println("#########Best speedup: "+maxSpeedup);
//                            System.out.println("==============================================================");
//                            
//                        } catch (Exception e) {
//                            Logger.getLogger(DistFileSystem.class.getName()).log(Level.SEVERE, null, e);
//                        }
//                        //Thread.sleep(1000);
//                    }
//                }               
//            }
//        }
//        
//        System.err.println("Best Speedup "+maxSpeedup);
//        System.out.println("Best its     "+bestIts);
//        System.out.println("Best steps   "+bestSteps);
//        System.out.println("Best k       "+bestK);
//        System.out.println("Best lamb    "+bestLam);
//        
//        
//        o.println("Best Speedup "+maxSpeedup);
//        o.println("Best its     "+bestIts);
//        o.println("Best steps   "+bestSteps);
//        o.println("Best k       "+bestK);
//        o.println("Best lamb    "+bestLam);
//       
//        o.close();
    }
}